home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / src_1218.zip / ICMP.C < prev    next >
C/C++ Source or Header  |  1991-08-14  |  7KB  |  264 lines

  1. /* Internet Control Message Protocol (ICMP)
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "iface.h"
  8. #include "ip.h"
  9. #include "icmp.h"
  10. #include "netuser.h"
  11.  
  12. struct mib_entry Icmp_mib[] = {
  13.     "",            0,
  14.     "icmpInMsgs",        0,
  15.     "icmpInErrors",        0,
  16.     "icmpInDestUnreachs",    0,
  17.     "icmpInTimeExcds",    0,
  18.     "icmpInParmProbs",    0,
  19.     "icmpInSrcQuenchs",    0,
  20.     "icmpInRedirects",    0,
  21.     "icmpInEchos",        0,
  22.     "icmpInEchoReps",    0,
  23.     "icmpInTimestamps",    0,
  24.     "icmpInTimestampReps",    0,
  25.     "icmpInAddrMasks",    0,
  26.     "icmpInAddrMaskReps",    0,
  27.     "icmpOutMsgs",        0,
  28.     "icmpOutErrors",    0,
  29.     "icmpOutDestUnreachs",    0,
  30.     "icmpOutTimeExcds",    0,
  31.     "icmpOutParmProbs",    0,
  32.     "icmpOutSrcQuenchs",    0,
  33.     "icmpOutRedirects",    0,
  34.     "icmpOutEchos",        0,
  35.     "icmpOutEchoReps",    0,
  36.     "icmpOutTimestamps",    0,
  37.     "icmpOutTimestampReps",    0,
  38.     "icmpOutAddrMasks",    0,
  39.     "icmpOutAddrMaskReps",    0,
  40. };
  41.  
  42. /* Process an incoming ICMP packet */
  43. void
  44. icmp_input(iface,ip,bp,rxbroadcast)
  45. struct iface *iface;    /* Incoming interface (ignored) */
  46. struct ip *ip;        /* Pointer to decoded IP header structure */
  47. struct mbuf *bp;    /* Pointer to ICMP message */
  48. int rxbroadcast;
  49. {
  50.     struct icmplink *ipp;
  51.     struct mbuf *tbp;
  52.     struct icmp icmp;    /* ICMP header */
  53.     struct ip oip;        /* Offending datagram header */
  54.     int16 type;        /* Type of ICMP message */
  55.     int16 length;
  56.  
  57.     icmpInMsgs++;
  58.     if(rxbroadcast){
  59.         /* Broadcast ICMP packets are to be IGNORED !! */
  60.         icmpInErrors++;
  61.         free_p(bp);
  62.         return;
  63.     }
  64.     length = ip->length - IPLEN - ip->optlen;
  65.     if(cksum(NULLHEADER,bp,length) != 0){
  66.         /* Bad ICMP checksum; discard */
  67.         icmpInErrors++;
  68.         free_p(bp);
  69.         return;
  70.     }
  71.     ntohicmp(&icmp,&bp);
  72.  
  73.     /* Process the message. Some messages are passed up to the protocol
  74.      * module for handling, others are handled here.
  75.      */
  76.     type = icmp.type;
  77.     
  78.     switch(uchar(type)){
  79.     case ICMP_TIME_EXCEED:    /* Time-to-live Exceeded */
  80.     case ICMP_DEST_UNREACH:    /* Destination Unreachable */
  81.     case ICMP_QUENCH:    /* Source Quench */
  82.         switch(uchar(type)){
  83.         case ICMP_TIME_EXCEED:    /* Time-to-live Exceeded */
  84.             icmpInTimeExcds++;
  85.             break;
  86.         case ICMP_DEST_UNREACH:    /* Destination Unreachable */
  87.             icmpInDestUnreachs++;
  88.             break;
  89.         case ICMP_QUENCH:    /* Source Quench */
  90.             icmpInSrcQuenchs++;
  91.             break;
  92.         }
  93.         ntohip(&oip,&bp);    /* Extract offending IP header */
  94.         if(Icmp_trace){
  95.             printf("ICMP from %s:",inet_ntoa(ip->source));
  96.             printf(" dest %s %s",inet_ntoa(oip.dest),
  97.              smsg(Icmptypes,ICMP_TYPES,uchar(type)));
  98.             switch(uchar(type)){
  99.             case ICMP_TIME_EXCEED:
  100.                 printf(" %s\n",
  101.                  smsg(Exceed,NEXCEED,uchar(icmp.code)));
  102.                 break;
  103.             case ICMP_DEST_UNREACH:
  104.                 printf(" %s\n",
  105.                  smsg(Unreach,NUNREACH,uchar(icmp.code)));
  106.                 break;
  107.             default:
  108.                 printf(" %u\n",uchar(icmp.code));
  109.                 break;
  110.             }
  111.         }
  112.         for(ipp = Icmplink;ipp->funct != NULL;ipp++)
  113.             if(ipp->proto == oip.protocol)
  114.                 break;
  115.         if(ipp->funct != NULL){
  116.             (*ipp->funct)(ip->source,oip.source,oip.dest,icmp.type,
  117.              icmp.code,&bp);
  118.         }
  119.         break;
  120.     case ICMP_ECHO:        /* Echo Request */
  121.         /* Change type to ECHO_REPLY, recompute checksum,
  122.          * and return datagram.
  123.          */
  124.         icmpInEchos++;
  125.         icmp.type = ICMP_ECHO_REPLY;
  126.         if((tbp = htonicmp(&icmp,bp)) == NULLBUF){
  127.             free_p(bp);
  128.             return;
  129.         }
  130.         icmpOutEchoReps++;
  131.         ip_send(ip->dest,ip->source,ICMP_PTCL,ip->tos,0,tbp,length,0,0);
  132.         return;
  133.     case ICMP_REDIRECT:    /* Redirect */
  134.         icmpInRedirects++;
  135.         break;
  136.     case ICMP_PARAM_PROB:    /* Parameter Problem */
  137.         icmpInParmProbs++;
  138.         break;
  139.     case ICMP_ECHO_REPLY:    /* Echo Reply */
  140.         icmpInEchoReps++;
  141.         echo_proc(ip->source,ip->dest,&icmp,bp);
  142.         bp = NULLBUF;    /* so it won't get freed */
  143.         break;
  144.     case ICMP_TIMESTAMP:    /* Timestamp */
  145.         icmpInTimestamps++;
  146.         break;
  147.     case ICMP_TIME_REPLY:    /* Timestamp Reply */
  148.         icmpInTimestampReps++;
  149.         break;
  150.     case ICMP_INFO_RQST:    /* Information Request */
  151.         break;
  152.     case ICMP_INFO_REPLY:    /* Information Reply */
  153.         break;
  154.     }
  155.     free_p(bp);
  156. }
  157. /* Return an ICMP response to the sender of a datagram.
  158.  * Unlike most routines, the callER frees the mbuf.
  159.  */
  160. int
  161. icmp_output(ip,data,type,code,args)
  162. struct ip *ip;        /* Header of offending datagram */
  163. struct mbuf *data;    /* Data portion of datagram */
  164. char type,code;        /* Codes to send */
  165. union icmp_args *args;
  166. {
  167.     struct mbuf *bp = NULLBUF;
  168.     struct icmp icmp;    /* ICMP protocol header */
  169.     int16 dlen;        /* Length of data portion of offending pkt */
  170.     int16 length;        /* Total length of reply */
  171.  
  172.     if(ip == NULLIP)
  173.         return -1;
  174.     if(uchar(ip->protocol) == ICMP_PTCL){
  175.         /* Peek at type field of ICMP header to see if it's safe to
  176.          * return an ICMP message
  177.          */
  178.         switch(uchar(data->data[0])){
  179.         case ICMP_ECHO_REPLY:
  180.         case ICMP_ECHO:
  181.         case ICMP_TIMESTAMP:
  182.         case ICMP_TIME_REPLY:
  183.         case ICMP_INFO_RQST:
  184.         case ICMP_INFO_REPLY:
  185.             break;    /* These are all safe */
  186.         default:
  187.             /* Never send an ICMP error message about another
  188.              * ICMP error message!
  189.              */
  190.             return -1;
  191.         }
  192.     }
  193.     /* Compute amount of original datagram to return.
  194.      * We return the original IP header, and up to 8 bytes past that.
  195.      */
  196.     dlen = min(8,len_p(data));
  197.     length = dlen + ICMPLEN + IPLEN + ip->optlen;
  198.     /* Take excerpt from data portion */
  199.     if(data != NULLBUF && dup_p(&bp,data,0,dlen) == 0)
  200.         return -1;    /* The caller will free data */
  201.  
  202.     /* Recreate and tack on offending IP header */
  203.     if((data = htonip(ip,bp,IP_CS_NEW)) == NULLBUF){
  204.         free_p(bp);
  205.         icmpOutErrors++;
  206.         return -1;
  207.     }
  208.     icmp.type = type;
  209.     icmp.code = code;
  210.     icmp.args.unused = 0;
  211.     switch(uchar(icmp.type)){
  212.     case ICMP_PARAM_PROB:
  213.         icmpOutParmProbs++;
  214.         icmp.args.pointer = args->pointer;
  215.         break;
  216.     case ICMP_REDIRECT:
  217.         icmpOutRedirects++;
  218.         icmp.args.address = args->address;
  219.         break;
  220.     case ICMP_ECHO:
  221.         icmpOutEchos++;
  222.         break;
  223.     case ICMP_ECHO_REPLY:
  224.         icmpOutEchoReps++;
  225.         break;
  226.     case ICMP_INFO_RQST:
  227.         break;
  228.     case ICMP_INFO_REPLY:
  229.         break;
  230.     case ICMP_TIMESTAMP:
  231.         icmpOutTimestamps++;
  232.         break;
  233.     case ICMP_TIME_REPLY:
  234.         icmpOutTimestampReps++;
  235.         icmp.args.echo.id = args->echo.id;
  236.         icmp.args.echo.seq = args->echo.seq;
  237.         break;
  238.     case ICMP_ADDR_MASK:
  239.         icmpOutAddrMasks++;
  240.         break;
  241.     case ICMP_ADDR_MASK_REPLY:
  242.         icmpOutAddrMaskReps++;
  243.         break;
  244.     case ICMP_DEST_UNREACH:
  245.         if(icmp.code == ICMP_FRAG_NEEDED)
  246.             icmp.args.mtu = args->mtu;
  247.         icmpOutDestUnreachs++;
  248.         break;
  249.     case ICMP_TIME_EXCEED:
  250.         icmpOutTimeExcds++;
  251.         break;
  252.     case ICMP_QUENCH:
  253.         icmpOutSrcQuenchs++;
  254.         break;
  255.     }
  256.     icmpOutMsgs++;
  257.     /* Now stick on the ICMP header */
  258.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  259.         free_p(data);
  260.         return -1;
  261.     }
  262.     return ip_send(INADDR_ANY,ip->source,ICMP_PTCL,ip->tos,0,bp,length,0,0);
  263. }
  264.